#ifndef SPONGE_LIBSPONGE_TCP_FACTORED_HH
#define SPONGE_LIBSPONGE_TCP_FACTORED_HH

#include "tcp_config.hh"
#include "tcp_receiver.hh"
#include "tcp_sender.hh"
#include "tcp_state.hh"

#include <unordered_map>

#define SC_UINT(n) static_cast<uint32_t>(n)

class TCPConnection;

//! \brief A complete endpoint of a TCP connection
class TCPConnection {
    static int num;
    int _this_num;
  private:
    TCPConfig _cfg;
    TCPReceiver _receiver{_cfg.recv_capacity};
    TCPSender _sender{_cfg.send_capacity, _cfg.rt_timeout, _cfg.fixed_isn};

    //! outbound queue of segments that the TCPConnection wants sent
    std::queue<TCPSegment> _segments_out{};

    //! Should the TCPConnection stay active (and keep ACKing)
    //! for 10 * _cfg.rt_timeout milliseconds after both streams have ended,
    //! in case the remote TCPConnection doesn't know we've received its whole stream?
    bool _linger_after_streams_finish{true};

    size_t _Linger_Time;

    WrappingInt32 _isn = WrappingInt32(0);

    size_t _timewait_start = SIZE_MAX;

    size_t _last_segment_recved_time = 0;

    size_t _cur_time = 0;

    bool _newest_is_pure_ack_seg = false;

    //bool _fin_recvd = false;

    struct {
        bool fin_recvd = false;
        uint64_t fin_abs_index = UINT64_MAX;
    } _fin_record{};

    // const TCPState _reset_state;
    TCPState::State _cur_state = TCPState::State::CLOSED;
    std::vector<TCPState> _official_state;
    void _update_state() {
        auto &&tcpstate = state();
        //printf("%s\n", tcpstate.name().c_str());
        for(int i = 0; i < 12; ++i){
            if(tcpstate == _official_state[i]) {
                _cur_state = static_cast<TCPState::State>(&_official_state[i] - &_official_state[0]);
                break;
            }
        }
//        auto &&iter = std::find(_official_state.begin(), _official_state.end(), state());
//
//        if(iter != _official_state.end())
//            _cur_state = static_cast<TCPState::State>(&(*iter) - &(*_official_state.begin()));
    }

//    enum SendMask {
//        SEND_FIN = 1 << 5,
//        SEND_SYN = 1 << 6,
//        SEND_RST = 1 << 7,
//        SEND_ACK = 1 << 8,
//    };

// 4位Op，4位Recv，4位State
    enum RecvMask {
        RECV_FIN = 1 << 4,
        RECV_SYN = 1 << 5,
        RECV_RST = 1 << 6,
        RECV_ACK = 1 << 7
    };

    enum OperationMask {
        OP_CLOSE = 1 << 8,
        OP_SEND = 1 << 9,
        OP_CONNECT = 1 << 10,
        OP_LISTEN = 1 << 11
    };

    union RecvOp {
        uint32_t recvs;
        uint32_t ops;
    };

    union InfoCodeWrap {
        uint32_t uint_value;
        struct InfoCode {
            uint32_t state_info: 4;
            uint32_t recv_op_info: 4;
            uint32_t padding: 24;

            InfoCode(uint32_t state, RecvOp recv_op)
                : state_info(state)
                , recv_op_info((recv_op.recvs >> 4) + (recv_op.ops >> 8))
                , padding(0){}
        } info_code;

        InfoCodeWrap(TCPState::State state, RecvOp recv_op): info_code(SC_UINT(state), recv_op){}
    };

    void _send_helper();

    void _closed_connect_handler();
    void _listen_send_handler();
    void _listen_close_handler();
    void _listen_handshake2_handler();
    void _syn_sent_sim_open_handler();
    void _syn_sent_handshake3_handler();
    void _syn_sent_close_handler();
    void _syn_recvd_ack_handler();
    void _syn_recvd_fin_ack_handler();
    void _syn_recvd_rst_handler();
    void _syn_recvd_close_handler();
    void _established_active_close_handler();
    void _established_passive_close_handler();
    void _established_ack_transmit_handler();
    void _fin_wait_1_ack_handler();
    void _fin_wait_1_fin_handler();
    void _fin_wait_1_fin_ack_handler();
    void _fin_wait_2_fin_handler();
    void _fin_wait_2_ack_handler();
    void _closing_ack_handler();
    void _time_wait_handler();
    void _close_wait_close_handler();
    void _close_wait_ack_handler();
    void _last_ack_handler();
    void _rst_handler();

    static const std::unordered_map<uint32_t, void (TCPConnection::*)()> _code_handler_map;
    //static const std::unordered_map<uint32_t, uint32_t> _code_index_map;

  public:
    //! \name "Input" interface for the writer
    //!@{

    //! \brief Initiate a connection by sending a SYN segment
    // @TODO 发送SYN
    void connect();

    //! \brief Write data to the outbound byte stream, and send it over TCP if possible
    //! \returns the number of bytes from `data` that were actually written.
    // @TODO 发送：写入outbound
    size_t write(const std::string &data);

    //! \returns the number of `bytes` that can be written right now.
    // sender的capacity还有多少
    size_t remaining_outbound_capacity() const;

    //! \brief Shut down the outbound byte stream (still allows reading incoming data)
    // @TODO 发送端关闭
    void end_input_stream();
    //!@}

    //! \name "Output" interface for the reader
    //!@{

    //! \brief The inbound byte stream received from the peer
    // 接收端的inbound
    ByteStream &inbound_stream() { return _receiver.stream_out(); }
    //!@}

    //! \name Accessors used for testing

    //!@{
    //! \brief number of bytes sent and not yet acknowledged, counting SYN/FIN each as one byte
    size_t bytes_in_flight() const;
    //! \brief number of bytes not yet reassembled
    size_t unassembled_bytes() const;
    //! \brief Number of milliseconds since the last segment was received
    size_t time_since_last_segment_received() const;
    //!< \brief summarize the state of the sender, receiver, and the connection
    TCPState state() const { return {_sender, _receiver, active(), _linger_after_streams_finish}; };
    //!@}

    //! \name Methods for the owner or operating system to call
    //!@{

    //! Called when a new segment has been received from the network
    // @TODO 收到segment
    void segment_received(const TCPSegment &seg);

    //! Called periodically when time elapses
    // @TODO tick
    void tick(const size_t ms_since_last_tick);

    //! \brief TCPSegments that the TCPConnection has enqueued for transmission.
    //! \note The owner or operating system will dequeue these and
    //! put each one into the payload of a lower-layer datagram (usually Internet datagrams (IP),
    //! but could also be user datagrams (UDP) or any other kind).
    std::queue<TCPSegment> &segments_out() { return _segments_out; }

    //! \brief Is the connection still alive in any way?
    //! \returns `true` if either stream is still running or if the TCPConnection is lingering
    //! after both streams have finished (e.g. to ACK retransmissions from the peer)
    bool active() const;
    //!@}

    //! Construct a new connection from a configuration
    explicit TCPConnection(const TCPConfig &cfg) : _this_num(++num), _cfg{cfg}, _Linger_Time(10 * cfg.rt_timeout)
        , _official_state(std::vector<TCPState>()) {
        //_update_state();
        for(int i = 0; i < 12; ++i){
            _official_state.emplace_back(static_cast<TCPState::State>(i));
        }
    }

    //! \name construction and destruction
    //! moving is allowed; copying is disallowed; default construction not possible

    //!@{
    ~TCPConnection();  //!< destructor sends a RST if the connection is still open
    TCPConnection() = delete;
    TCPConnection(TCPConnection &&other) = default;
    TCPConnection &operator=(TCPConnection &&other) = default;
    TCPConnection(const TCPConnection &other) = delete;
    TCPConnection &operator=(const TCPConnection &other) = delete;
    //!@}

    //uint32_t getLinger() const{return static_cast<uint32_t >(_linger_after_streams_finish);}
};

//const std::unordered_map<uint32_t, uint32_t> TCPConnection::_code_index_map = []() -> const std::unordered_map<uint32_t, uint32_t>&& {
//    std::unordered_map<uint32_t, uint32_t> umap;
//    uint32_t i = 0;
//    RecvOp ro{};
//    ro.ops = OperationMask::OP_CONNECT;
//    umap[InfoCodeWrap(TCPState::State::CLOSED, ro).uint_value] = i++;
//    ro.ops = OperationMask::OP_SEND;
//    umap[InfoCodeWrap(TCPState::State::LISTEN, ro).uint_value] = i++;
//    ro.recvs = RecvMask::RECV_SYN;
//    umap[InfoCodeWrap(TCPState::State::LISTEN, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::SYN_SENT, ro).uint_value] = i++;
//    ro.recvs |= RecvMask::RECV_ACK;
//    umap[InfoCodeWrap(TCPState::State::SYN_SENT, ro).uint_value] = i++;
//    ro.recvs = RecvMask::RECV_ACK;
//    umap[InfoCodeWrap(TCPState::State::SYN_RCVD, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::FIN_WAIT_1, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::CLOSING, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::LAST_ACK, ro).uint_value] = i++;
//    ro.recvs = RecvMask::RECV_FIN;
//    umap[InfoCodeWrap(TCPState::State::ESTABLISHED, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::FIN_WAIT_1, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::FIN_WAIT_2, ro).uint_value] = i++;
//    ro.recvs |= RecvMask::RECV_ACK;
//    umap[InfoCodeWrap(TCPState::State::FIN_WAIT_1, ro).uint_value] = i++;
//    ro.ops = OperationMask::OP_CLOSE;
//    umap[InfoCodeWrap(TCPState::State::LISTEN, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::SYN_SENT, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::SYN_RCVD, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::ESTABLISHED, ro).uint_value] = i++;
//    umap[InfoCodeWrap(TCPState::State::CLOSE_WAIT, ro).uint_value] = i++;
//    ro.recvs = RecvMask::RECV_RST;
//    umap[InfoCodeWrap(TCPState::State::SYN_RCVD, ro).uint_value] = i++;
//
//    return std::move(umap);
//}();

#endif  // SPONGE_LIBSPONGE_TCP_FACTORED_HH
